﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using Avivo.Common;

namespace Avivo.Tools.Sprite
{
	internal static class SpriteRenderEngine
	{
		public static ILogger Logger;

		/// <summary>
		/// Replaces constants and renders xaml content to a raster image file.
		/// </summary>
		/// <param name="rawXamlContent"></param>
		/// <param name="targetPath"></param>
		/// <param name="messages"></param>
		public static bool RenderXaml(string rawXamlContent, string targetPath, Dictionary<string, string> messages)
		{
			string xaml = rawXamlContent;
			foreach (string key in messages.Keys)
			{
				string value = messages[key] ?? string.Empty;
				//value = HttpContext.Current.Server.HtmlDecode(value);
				//value = HttpContext.Current.Server.HtmlDecode(value);
				//value = HttpContext.Current.Server.HtmlEncode(value);
				xaml = xaml.Replace("{Binding " + key + "}", value);

				if (key == "Text")
				{
					//Binding without path should be the same as binding with path "Text"
					xaml = xaml.Replace("{Binding}", value);
				}
			}

			//Create a temporary filename
			string tempFilename = Path.Combine(Settings.AppBasePath, "Temp\\Raster\\" + Guid.NewGuid().ToString() + ".xaml");
			string tempDirectory = Path.GetDirectoryName(tempFilename);
			if (!Directory.Exists(tempDirectory))
			{
				Directory.CreateDirectory(tempDirectory);
			}
			File.WriteAllText(tempFilename, xaml);

			//Render xaml to image
			Converter.XamlToPng(tempFilename, targetPath);

			//Delete temporary file
			File.Delete(tempFilename);

			bool completed = File.Exists(targetPath);
			return completed;
		}

		public static bool RenderXaml(string rawXamlContent, string targetPath, string text)
		{
			Dictionary<string, string> messages = new Dictionary<string, string>();
			messages.Add("Text", text);
			return RenderXaml(rawXamlContent, targetPath, messages);
		}

		public static bool RenderXamlFromPath(string xamlPath, string imagePath, Dictionary<string, string> messages)
		{
			return RenderXaml(File.ReadAllText(xamlPath), imagePath, messages);
		}

		public static bool RenderXamlFromPath(string xamlPath, string imagePath, string text)
		{
			Dictionary<string, string> messages = new Dictionary<string, string>();
			messages.Add("Text", text);
			return RenderXaml(File.ReadAllText(xamlPath), imagePath, messages);
		}

		public static bool RenderSprite(ref SpriteGrid grid, string imagePath)
		{
			try
			{
				string tempDirectory = Settings.AppBasePath + "Temp\\Sprite\\" + Guid.NewGuid().ToString() + "\\";
				Directory.CreateDirectory(tempDirectory);

				#region Render each image
				foreach (var row in grid)
				{
					try
					{
						foreach (var item in row)
						{
							//Generate target path
							item.Target = tempDirectory + Utils.CreateMD5(item.Source + item.Name + item.Text) + ".png";

							//Convert xaml to raster
							if (item.Messages != null && item.Messages.Count > 0)
							{
								//Multiple constants
								RenderXamlFromPath(item.Source, item.Target, item.Messages);
							}
							else
							{
								//Single constant - {Binding Text}
								RenderXamlFromPath(item.Source, item.Target, item.Text);
							}

							//Check if rendered
							if (!File.Exists(item.Target))
							{
								throw new Exception("Cannot convert xaml to raster: " + item.Target);
							}

							//Get image size
							Image image = Image.FromFile(item.Target);
							SizeF size = image.PhysicalDimension;
							item.Width = (int)size.Width;
							item.Height = (int)size.Height;
							image.Dispose();
						}
					}
					catch
					{
					}
				}
				#endregion

				#region Container dimensions
				int totalWidth = 0;
				int totalHeight = 0;

				foreach (var row in grid)
				{
					//Calculating container dimensions...
					totalWidth = Math.Max(totalWidth, row.Width);
					totalHeight += row.Height;
				}

				if (totalWidth == 0 || totalHeight == 0)
				{
					throw new Exception("Width or height cannot be 0!");
				}
				#endregion
				
				#region Generate large image
				Bitmap bitmap = new Bitmap(totalWidth, totalHeight);
				Graphics g = Graphics.FromImage(bitmap);

				int y = 0;
				foreach (var row in grid)
				{
					try
					{
						int x = 0;
						foreach (var item in row)
						{
							item.X = x;
							item.Y = y;

							Image image = Image.FromFile(item.Target);
							g.DrawImage(image, x, y, item.Width, item.Height);
							image.Dispose();

							x += item.Width;
						}
						y += row.Height;
					}
					catch
					{
					}
				}

				string dir = Path.GetDirectoryName(imagePath);
				if (!Directory.Exists(dir))
				{
					Directory.CreateDirectory(dir);
				}
				bitmap.Save(imagePath, ImageFormat.Png);
				bitmap.Dispose();
				g.Dispose();
				#endregion

				//Clear garbage collector
				GC.Collect();
				GC.WaitForPendingFinalizers();

				Directory.Delete(tempDirectory, true);
				return File.Exists(imagePath);
			}
			catch (Exception ex)
			{
				//Logger.Log(ex, EventLogEntryType.Error);
				return false;
			}
		}
	}	
}
